#include "Decoder.h"
#include <pthread.h>

Decoder::Decoder()
{

}

Decoder::~Decoder()
{

}

int Decoder::init(AVCodecContext *avctx, shared_ptr<PacketQueue> queue, SDL_cond *cond)
{
    pkt = av_packet_alloc();
    if (!pkt)
        return AVERROR(ENOMEM);
    this->avctx = avctx;
    this->queue = queue;
    this->empty_queue_cond = cond;
    this->start_pts = AV_NOPTS_VALUE;
    this->pkt_serial = 1;
    // 激活队列
    queue->packet_queue_start();
    return 0;
}

void Decoder::destroy()
{
    av_packet_free(&pkt);
    avcodec_free_context(&avctx);
}

int Decoder::decoder_decode_frame(AVFrame *frame)
{
    int ret = AVERROR(EAGAIN);
    for(;;) {
        // 流连续情况下获取解码后的帧
        if(queue->packet_queue_serial() == pkt_serial) {
            do
            {
                if(queue->packet_queue_isAbort())
                    return -1; // 是否请求退出
                switch (avctx->codec_type) {
                case AVMEDIA_TYPE_AUDIO:
                    ret = avcodec_receive_frame(avctx, frame);
                    if(ret >= 0) {
                        AVRational tb = (AVRational){1, frame->sample_rate};
                        if (frame->pts != AV_NOPTS_VALUE)
                            // 如果frame->pts正常则先将其从pkt_timebase转成{1, frame->sample_rate}
                            // pkt_timebase实质就是stream->time_base
                            frame->pts = av_rescale_q(frame->pts, avctx->pkt_timebase, tb);
                        else if(next_pts != AV_NOPTS_VALUE)
                            // 如果frame->pts不正常则使用上一帧更新的next_pts和next_pts_tb
                            // 转成{1, frame->sample_rate}
                            frame->pts = av_rescale_q(next_pts, next_pts_tb, tb);
                        if(frame->pts != AV_NOPTS_VALUE) {
                            // 根据当前帧的pts和nb_samples预估下一帧的pts
                            next_pts = frame->pts + frame->nb_samples;
                            // 设置timebase
                            next_pts_tb = tb;
                        }
                    }
                    break;
                default:
                    break;
                }
                // 读完了
                if(ret == AVERROR_EOF) {
                    finished = pkt_serial;        // 置为空闲
                    avcodec_flush_buffers(avctx); // 冲刷解码器
                    return 0;
                }
                // 读到数据帧
                if (ret >= 0)
                    return 1;
            }while(ret != AVERROR(EAGAIN));
        }

        //获取一个packet，如果播放序列不一致(数据不连续)则过滤掉“过时”的packet
        do{
            // 如果没有可读的数据则唤醒 readThread
            if (queue->packet_queue_packet_num() == 0)
                SDL_CondSignal(empty_queue_cond);
            if (packet_pending) {
                packet_pending = 0;
            } else {
                uint32_t old_serial = pkt_serial;
                // 阻塞的方式读packet
                if (queue->packet_queue_get(pkt, 1, &pkt_serial) < 0)
                    return -1;
                if (old_serial != pkt_serial) {
                    avcodec_flush_buffers(avctx);
                    finished = 0;
                    next_pts = start_pts;
                    next_pts_tb = start_pts_tb;
                }
            }
            if (queue->packet_queue_serial() == pkt_serial)
                break;
            av_packet_unref(pkt); // 如果播放序列不一致 要丢弃并释放pkt
        }while(true);

        // 3 .将packet送入解码器
        if (avcodec_send_packet(avctx, pkt) == AVERROR(EAGAIN)) {
            av_log(avctx, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
            packet_pending = 1; // 这里保证了这次获取的pkt不会被丢弃。下次循环时就重新使用该pkt
        } else {
            av_packet_unref(pkt);
        }
    }
}
